package com.mnsq.common.service.impl;

import com.mnsq.common.bean.condition.CommonBaseCondition;
import com.mnsq.common.bean.conf.ThreadLocalUserId;
import com.mnsq.common.bean.dto.PageInfo;
import com.mnsq.common.bean.entity.CommonEntity;
import com.mnsq.common.bean.enums.CountRecordType;
import com.mnsq.common.bean.enums.StatusEnum;
import com.mnsq.common.dao.BaseDao;
import com.mnsq.common.helper.RedisHelper;
import com.mnsq.common.service.BaseService;
import com.mnsq.common.tools.jpa.JpaExample;
import com.mnsq.common.tools.tool.BeanCopyUtils;
import com.mnsq.common.tools.tool.UUIDUtils;
import matrix.module.common.bean.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author 周俭
 */
@Service
public class BaseServiceImpl<T extends CommonEntity, C extends CommonBaseCondition> implements BaseService<T, C> {

    @Autowired
    private BaseDao<T> baseDao;

    @Autowired
    private RedisHelper redisHelper;

    @Override
    public Result<PageInfo<T>> queryPage(C c) {
        PageInfo<T> info = new PageInfo<>();
        if (c.getStatus() == null) {
            c.setStatus(StatusEnum.STATUS_VALID.value);
        }
        Page<T> all = baseDao.findAll(JpaExample.getInstance().getExample(c, c.getInstance()),
                PageRequest.of(c.getPageNum(), c.getPageSize(),
                        Sort.by("createTime").descending()));
        info.setContent(all.getContent())
                .setTotalPages(all.getTotalPages())
                .setPageNum(c.getPageNum())
                .setTotalSize(all.getTotalElements());
        return Result.success(info);
    }

    @Override
    public Result<T> queryOne(C c) {
        if (c.getUnique() == null) {
            return Result.fail("unique is null");
        }
        // add the read times
        Long userId = ThreadLocalUserId.CURRENT_USER_ID.get();
        redisHelper.timesRecord(c.getUnique(), userId, CountRecordType.READ_TIMES.toString());
        Optional<T> one = baseDao.findOne(JpaExample.getInstance().getExample(c, c.getInstance()));
        return Result.success(one.orElse(null));
    }

    @Override
    public Result updateOne(T t) {
        T tc = null;
        try {
            tc = (T) t.getClass().newInstance();
            tc.setId(t.getId());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        Optional<T> one = baseDao.findOne(Example.of(tc));
        if (one.orElse(null) == null) {
            return Result.fail("find nothing.");
        }
        T t1 = one.get();
        BeanCopyUtils.copyNullProperties(t, t1);
        t1.setUpdateTime(new Date());
        t1.setUpdateUserId(ThreadLocalUserId.CURRENT_USER_ID.get());
        baseDao.saveAndFlush(t1);
        return Result.success(t1.getId());
    }

    @Override
    public Result add(T t) {
        if (t.getId() != null && t.getId() > 0L) {
            return updateOne(t);
        }
        t.createInit();
        t.setId(null);
        t.setUnique(UUIDUtils.getUnique());
        t.setCreateTime(new Date());
        t.setCreateUserId(ThreadLocalUserId.CURRENT_USER_ID.get());
        t.setUpdateTime(new Date());
        t.setUpdateUserId(ThreadLocalUserId.CURRENT_USER_ID.get());
        baseDao.saveAndFlush(t);
        return Result.success(t.getId());
    }

    @Override
    public Result del(C c) {
        Optional<T> one = baseDao.findOne(JpaExample.getInstance().getExample(c, c.getInstance()));
        if (one.isPresent()) {
            T t = one.get();
            t.setStatus(StatusEnum.STATUS_DEL.value);
            t.setUpdateTime(new Date());
            t.setUpdateUserId(ThreadLocalUserId.CURRENT_USER_ID.get());
            baseDao.saveAndFlush(t);
            return Result.success(t.getUnique());
        }
        return Result.success(true);
    }

    @Override
    public Result<List<T>> queryList(C c) {
        if (c.getStatus() == null) {
            c.setStatus(StatusEnum.STATUS_VALID.value);
        }
        return Result.success(baseDao.findAll(JpaExample.getInstance().getExample(c, c.getInstance()), Sort.by("createTime").descending()));
    }

}
